#include "dissolved_oxygen_sensor.h"

unsigned char DOS_Open[8] = {0x01, 0x03, 0x25, 0x00, 0x00, 0x00, 0x4E, 0xC6};
//unsigned char DOS_OpenSuccess[5] = {0x01, 0x03, 0x00, 0x20, 0xF0};
//unsigned char GetSensorData[8] = {0x01, 0x03, 0x2D, 0x00, 0x00, 0x02, 0xCD, 0x67};//测试命令
unsigned char GetSensorData[8] = {0x01, 0x03, 0x26, 0x00, 0x00, 0x06, 0xCE, 0x80}; //测试旧协议命令，带温度
unsigned char DOS_RecvData[100] = {0}; //接收溶解氧传感器的数据

pthread_t DOS_ThreadId = 0;

int g_D_time = 0;
int g_DOS_fd = 0;



pthread_mutex_t ods_mutex = PTHREAD_MUTEX_INITIALIZER; /*互斥锁*/

/*





*/
/*******************************************************************
** 函数名:     CRC16_2
** 函数描述:   用于modbus的crc校验，返回2个字节的16进制校验码。
** 参数：      crc：为0xFFFF buf：需要添加校验码的字符串 len：字符串长度
********************************************************************/
unsigned short CRC16_2(unsigned short crc, unsigned char *buf, int len)
{
    for (int pos = 0; pos < len; pos++)
    {
        crc ^= (unsigned short)buf[pos];
        for (int i = 8; i != 0; i--)
        {
            if ((crc & 0x0001) != 0)
            {
                crc >>= 1;
                crc ^= 0xA001;
            }
            else
            {
                crc >>= 1;
            }
        }
    }
    return crc;
}

/*



*/
/*******************************************************************
** 函数名:     Open_DOS
** 函数描述:   向传感器发送开始命令，传感器收到后会返回 开始成功
**              检测1秒，如果收到开始成功则返回1，否则返回0
** 参数：      无
********************************************************************/
int Open_DOS()
{
    int DataLen = sizeof(DOS_Open);
    SendDataUart(DOS_Open, DataLen, DOS_Type);
    unsigned char DOS_OpenSuccess[5] = {0x01, 0x03, 0x00, 0x20, 0xF0};
    int len = 0;
    for (int i = 0; i < 10; i++)
    {
        usleep(100000);
        RecvDataUart(DOS_RecvData, &len, DOS_Type);
        if (strcmp(DOS_RecvData, DOS_OpenSuccess) == 0)
        {
            printf("打开溶解氧传感器成功\n");
            memset(DOS_RecvData, 0, sizeof(DOS_RecvData));
            return 1;
        }
        memset(DOS_RecvData, 0, sizeof(DOS_RecvData));
    }
    return 0;
}
/*



*/
/*******************************************************************
** 函数名:     DOS_DataHandle
** 函数描述:   传感器数据处理。先进行crc校验，成功则解析数据为float类型
**             把数据回调出去。
** 返回值      成功返回0；失败返回-1
** 参数：      crc校验码，回调函数
********************************************************************/
int DOS_DataHandle(unsigned short crc, DOS_cb RecvData_Cb)
{
    pthread_mutex_lock(&ods_mutex); //互斥锁加锁
    unsigned short Crc = 0;
    int i = strlen(DOS_RecvData) - 2;
    memcpy(&Crc, &DOS_RecvData[i], 2);
    printf("Crc==%x\n", Crc);
    printf("crc==%x\n", crc);
    if (Crc != crc)
    {
        pthread_mutex_unlock(&ods_mutex); ////互斥锁解锁
        return -1;
    }
       
    float DOS_FloatData = 0;
    float temp_FloatData = 0;
    if (DOS_RecvData[0] == 0x01)
    {
    // for (size_t i = 0; i < 15; i++)
    // {
    // printf("%x\n", DOS_RecvData[i]);
    // }
    
      
        memcpy(&DOS_FloatData, &DOS_RecvData[11], 4);//溶解氧
        memcpy(&temp_FloatData, &DOS_RecvData[3], 4);//温度
        // printf("data==%.2f\n", DOS_FloatData);
        RecvData_Cb(DOS_FloatData, temp_FloatData, sizeof(DOS_FloatData), DOS_Type);
    }

    pthread_mutex_unlock(&ods_mutex); ////互斥锁解锁
    return 0;
}

/*



*/
/*******************************************************************
** 函数名:     DOS_Thread
** 函数描述:   处理溶解氧传感器的进程
** 参数：      回调函数
********************************************************************/
void *DOS_Thread(DOS_cb RecvData_Cb)
{
    //设置线程对Cancel信号的反应
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    /*同步取消，等到下一个取消点再取消*/
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    // pthread_detach(pthread_self()); //线程分离
    if (Open_DOS())
    {
        printf("溶解氧传感器初始化成功\n");
    }
    else
    {
        printf("溶解氧传感器初始化失败 错误==%x\n", DOS_RecvData);
    }

    while (1)
    {
        int DataLen = sizeof(GetSensorData);
        SendDataUart(GetSensorData, DataLen, DOS_Type);
        //serialPuts(g_DOS_fd, GetSensorData);
        int len = 0;
        RecvDataUart(DOS_RecvData, &len, DOS_Type);
        if (len >= 9)
        {
            unsigned short crc = CRC16_2(0xFFFF, DOS_RecvData, strlen(DOS_RecvData) - 2);
            DOS_DataHandle(crc, RecvData_Cb);
            memset(DOS_RecvData, 0, sizeof(DOS_RecvData));
        }
        usleep(g_D_time);
        pthread_testcancel(); //设置取消点
    }
}

/*



*/
/*******************************************************************
** 函数名:     DOS_init
** 函数描述:   给外部的初始化接口
** 参数：      回调函数地址，控制传感器输出数据频率的时间,串口名称，波特率
********************************************************************/
void DOS_init(DOS_cb RecvData_Cb, int time,char *uartPort,int baud)
{
    g_D_time = time;
    g_DOS_fd = serialOpen(uartPort, baud); //打开串口
    printf("DOS_fd==%d", g_DOS_fd);
    if ((pthread_create(&DOS_ThreadId, NULL, DOS_Thread, RecvData_Cb)) == -1)
    {
        printf("创建溶解氧线程错误!\n");
    }
}

/*


 
*/
/*******************************************************************
** 函数名:     RemoveInit
** 函数描述:   给外部的去初始化接口，调用时释放系统资源
** 参数：      无
********************************************************************/
int RemoveInit()
{
    pthread_mutex_destroy(&ods_mutex);
    void *threadRet = NULL;
    pthread_cancel(DOS_ThreadId); //退出线程
    int ret = pthread_join(DOS_ThreadId, &threadRet);
    printf("kill Thread:: %d, %d DOS_ThreadId:%d\r\n", ret, (int)threadRet, DOS_ThreadId);
    return ret;
}
/*




模拟溶解氧传感器 发送的数据
*/
void RecvDataUart(char *SendBuff, int *SendLen, int Type)
{
    if (Type == DOS_Type)
    {
        *SendLen = serialDataAvail(g_DOS_fd);
        if (SendLen >= 0)
        {
            for (int i = 0; i < *SendLen; i++)
            {
                SendBuff[i] = serialGetchar(g_DOS_fd);
            }
        }
        serialFlush(g_DOS_fd);
    }
}

/*


模拟溶解氧传感器 接收的数据
*/
void SendDataUart(char *SendBuff, int SendLen, int Type)
{
    if (Type == DOS_Type)
    {
        for (int i = 0; i < SendLen; i++)
        {
            serialPutchar(g_DOS_fd, SendBuff[i]);
        }
    }
}